package bb.lanxing.device.sgdevcie.viewmodel

import android.app.Application
import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import bb.lanxing.R
import bb.lanxing.device.sgdevcie.tool.XossDeviceConstants.DeviceUIState
import bb.lanxing.device.sgdevcie.utils.BleCompatScannerUtil
import bb.lanxing.device.sgdevcie.utils.FitParser
import bb.lanxing.device.sync.XossDeviceAutoSyncManager
import bb.lanxing.lib.base.BaseApplication
import bb.lanxing.lib.devices.api.ConnectionListener
import bb.lanxing.lib.devices.api.SmartDevice
import bb.lanxing.lib.devices.base.DeviceContext
import bb.lanxing.lib.devices.ble.XOSSSGFileHelper
import bb.lanxing.lib.devices.core.utils.DeviceHelper
import bb.lanxing.lib.devices.sgsettingentity.IDeletable
import bb.lanxing.lib.devices.sgsettingentity.gearprofile.GearProfileSettings
import bb.lanxing.lib.devices.sgsettingentity.routebook.Routebooks
import bb.lanxing.lib.devices.sgsettingentity.setting.CommonSettings
import bb.lanxing.lib.devices.sgsettingentity.userprofile.UserProfileSettings
import bb.lanxing.lib.devices.sgsettingentity.workout.Workout
import bb.lanxing.lib.devices.sgsettingentity.workout.Workouts
import bb.lanxing.lib.devices.sprint.Command
import bb.lanxing.lib.devices.sprint.Commands
import bb.lanxing.lib.devices.sprint.SprintListener
import bb.lanxing.lib.devices.sprint.XossDeviceController
import bb.lanxing.lib.devices.sprint.utils.BleBondUtil
import bb.lanxing.lib.devices.sprint.utils.DeviceControllerHelper
import bb.lanxing.lib.devices.utils.BleUtils
import bb.lanxing.lib.kt.ByteArrayExtKt
import bb.lanxing.manager.SharedManager
import bb.lanxing.model.database.Device
import bb.lanxing.model.device.GNSSInfoBean
import bb.lanxing.model.firmware.FirmwareDetailEntity
import bb.lanxing.mvvm.base.viewmodel.BaseViewModel
import bb.lanxing.mvvm.base.viewmodel.SingleLiveEvent
import bb.lanxing.mvvm.base.viewmodel.TipAction
import bb.lanxing.util.Log
import bb.lanxing.util.OnDeviceBondStateChangeListener
import bb.lanxing.util.debug.TransLogger
import bb.lanxing.util.extender.KotlinExtender.readText
import com.bes.bessdk.BesSdkConstants
import com.bes.sdk.utils.SettingsJsonUtils
import com.besall.allbase.common.utils.FileUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.ToastUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.coroutines.Continuation


class DeviceViewModel(application: Application) : BaseViewModel(application) {
    val gNSSInfoFlow: MutableSharedFlow<GNSSInfoBean> = MutableSharedFlow()
    var address: String? = null
    val commonSettingSharedFlow: MutableSharedFlow<CommonSettings> = MutableSharedFlow()
    val routebooksNotExist: MutableSharedFlow<Boolean> = MutableSharedFlow()
    private var connectCallBack: ConnectCallBack? = null
    var connectionListener = ConnectionListener { smartDevice: SmartDevice?, newState, _ ->
        smartDevice?.let {
            if (it.address == address) {
                if (newState == 1) {
                    dfuDeviceScanner?.scan()
                    isConnectFromUser = true
                    applyUIState(DeviceUIState.CONNECTING)
                } else if (newState == 2) {
                    dfuDeviceScanner?.cancel()
                    dfuDeviceFound = null
                    connectCallBack?.onConnectResult(true)
                    applyUIState(DeviceUIState.CONNECTED)
                    isConnectFromUser = false
                } else if (newState != 4) {
                    if (newState == 8) {
                        Log.d("wangsm_bt", " wangsm,connectionListener -->  onServiceDiscovered")
                        connectCallBack?.onServiceDiscovered()
                    }
                } else {
                    onDeviceDisconnect()
                    dfuDeviceScanner?.scan()
                    if (isConnectFromUser) {
                        connectCallBack?.onConnectResult(false)
                        applyUIState(DeviceUIState.CONNECT_FAIL)
                        return@ConnectionListener
                    }
                    applyUIState(DeviceUIState.OFFLINE_CONNECTION_LOST)
                }
            }
        }
    }

    val delayInPeer = 200L
    var deviceName: String? = null
    var deviceType: Int = 0
    val deviceUIStateStateFlow: MutableStateFlow<DeviceUIState> =
        MutableStateFlow(DeviceUIState.UNKNOWN)
    var dfuDeviceFound: Pair<String, String>? = null
    private var dfuDeviceScanner: BleCompatScannerUtil? = null
    val errorLogSharedFlow: MutableSharedFlow<Pair<Boolean, File>> = MutableSharedFlow()
    private var fileDeleteCallBack: FileDeleteCallBack? = null
    private var fileGetCallBack: FileGetCallBack? = null
    private var fileSendCallBack: FileSendCallBack? = null
    val fileSharedFlow: MutableSharedFlow<File> = MutableSharedFlow()
    val firmwareDetailEntityFlow: MutableLiveData<FirmwareDetailEntity> = MutableLiveData()
    val fitParser: FitParser by lazy { FitParser() }
    val gearProfileSharedFlow: MutableSharedFlow<GearProfileSettings> = MutableSharedFlow()
    private var gnssExpiredTime: MutableStateFlow<Long> = MutableStateFlow(-1L)
    var isConnectFromUser: Boolean = false
    var isInitAll: Boolean = false
    var isInitProfile: Boolean = false
    val memoryUsageFlow: MutableStateFlow<Pair<Long, Long>> = MutableStateFlow(Pair(0L, 0L))
    val exceptionMessage: MutableSharedFlow<Int> = MutableSharedFlow()
    val mutex: Mutex = Mutex()
    private val onDeviceBondStateChangeListener: OnDeviceBondStateChangeListener =
        object : OnDeviceBondStateChangeListener {
            override fun onBondFailed(address: String) {
            }

            override fun onBondLost(address: String) {
            }

            override fun onBonded(address: String) {
            }

            override fun onBonding(address: String) {
                if (!BleBondUtil.isThisDeviceBounded(address)) {
                    this@DeviceViewModel.removeDeviceByUnBond()
                }
            }

            override fun targetAddress(): String {
                return ""
            }
        }
    val panelsFileLiveData: MutableLiveData<File> = MutableLiveData()
    val progressStateFlow: MutableStateFlow<Float> = MutableStateFlow(0.0f)
    val readDisStateLiveData: SingleLiveEvent<Boolean> = SingleLiveEvent()
    val removeDeviceStateLiveEvent: SingleLiveEvent<Boolean> = SingleLiveEvent()
    val routeBookListFlow: MutableSharedFlow<Routebooks> = MutableSharedFlow()
    val sendCommonSettingSharedFlow: MutableSharedFlow<Boolean> = MutableSharedFlow()
    val sendGearProfileSharedFlow: MutableSharedFlow<Boolean> = MutableSharedFlow()
    val sendPanelResultFlow: MutableSharedFlow<Boolean> = MutableSharedFlow()
    val sendRouteBookSharedFlow: MutableSharedFlow<Pair<Long, Boolean>> = MutableSharedFlow()
    val sendUserProfileSharedFlow: MutableSharedFlow<Boolean> = MutableSharedFlow()
    val userProfileSharedFlow: MutableSharedFlow<UserProfileSettings> = MutableSharedFlow()
    val workoutListFlow: MutableSharedFlow<Workouts> = MutableSharedFlow()
    val workoutSyncIndexStateFlow: MutableSharedFlow<Pair<Int, Int>> = MutableSharedFlow()

    var xossDeviceController: XossDeviceController? = null
    private var xossDeviceListener = object : SprintListener {
        override fun onProgressUpdate(command: Command, f: Float) {
            if (command.cmd.toInt() == 5) {
                applyProgress(f)
            }
            if (command.cmd.toInt() != 7) {
                return
            }
            applyProgress(f)
        }

        override fun onCmdStatus(command: Command, i: Int, bArr: ByteArray?) {//?add by bb
            val fileGetCallBack: FileGetCallBack?
            val fileGetCallBack2: FileGetCallBack?
            val fileSendCallBack: FileSendCallBack?
            val fileSendCallBack2: FileSendCallBack?
            val fileDeleteCallBack: FileDeleteCallBack?
            val fileDeleteCallBack2: FileDeleteCallBack?
            val deviceViewModel = this@DeviceViewModel
            val cmd = command.cmd
            if (cmd.toInt() != 5) {
                if (cmd.toInt() != 7) {
                    if (cmd.toInt() == 13) {
                        if (i == 0) {
                            deviceViewModel.applyUIState(DeviceUIState.CONNECTED)
                            fileDeleteCallBack2 = deviceViewModel.fileDeleteCallBack
                            if (fileDeleteCallBack2 != null) {
                                deviceViewModel.d("File delete success : " + fileDeleteCallBack2.fileName)
                                fileDeleteCallBack2.onFileDeleteSuccess()
                                deviceViewModel.fileDeleteCallBack = null
                            }
                        } else {
                            deviceViewModel.applyUIState(DeviceUIState.CONNECTED)
                            fileDeleteCallBack = deviceViewModel.fileDeleteCallBack
                            if (fileDeleteCallBack != null) {
                                deviceViewModel.d("File delete failed : " + fileDeleteCallBack.fileName)
                                fileDeleteCallBack.onFileDeleteFailed()
                                deviceViewModel.fileDeleteCallBack = null
                            }
                        }
                    }
                } else if (i == 0) {
                    deviceViewModel.applyUIState(DeviceUIState.CONNECTED)
                    fileSendCallBack2 = deviceViewModel.fileSendCallBack
                    if (fileSendCallBack2 != null) {
                        deviceViewModel.d("File send success : " + fileSendCallBack2.file)
                        fileSendCallBack2.onFileSendSuccess()
                        deviceViewModel.fileSendCallBack = null
                    }
                } else {
                    deviceViewModel.applyUIState(DeviceUIState.CONNECTED)
                    fileSendCallBack = deviceViewModel.fileSendCallBack
                    if (fileSendCallBack != null) {
                        deviceViewModel.d("File send failed : " + fileSendCallBack.file)
                        fileSendCallBack.onFileSendFailed()
                        deviceViewModel.fileSendCallBack = null
                    }
                }
            } else if (i == -4) {
                fileGetCallBack = deviceViewModel.fileGetCallBack
                if (fileGetCallBack != null) {
                    deviceViewModel.d("File got failed : " + fileGetCallBack.fileName)
                    fileGetCallBack.onFileGetFailed()
                    deviceViewModel.fileGetCallBack = null
                }
            } else if (i != 0) {
                deviceViewModel.applyUIState(DeviceUIState.CONNECTED)
                fileGetCallBack2 = deviceViewModel.fileGetCallBack
                if (fileGetCallBack2 != null) {
                    deviceViewModel.d("File got failed : " + fileGetCallBack2.fileName)
                    fileGetCallBack2.onFileGetFailed()
                    deviceViewModel.fileGetCallBack = null
                }
            }
            deviceViewModel.catchStatus(command.cmd, bArr)
        }

        override fun onFileReceived(path: String) {
            applyUIState(DeviceUIState.CONNECTED)
            val name = File(path).name
            val obj = name.trim()

            if (fileGetCallBack == null) {//fileName == null ||
                Log.d("wangsm_bt", " wangsm,onFileReceived ,fileGetCallBack,return:")
                return;
            }

            val fileName = fileGetCallBack?.fileName
            Log.d("wangsm_bt", " wangsm,onFileReceived,fileName:  $fileName")
            Log.d("wangsm_bt", " wangsm,onFileReceived,path:  $path")
            //add by bb for name null,return
            if (fileName == null) {//fileName == null ||
                Log.d("wangsm_bt", " wangsm,onFileReceived the name is null ,return")
                return;
            }
            if (obj == null) {//fileName == null ||
                Log.d("wangsm_bt", " wangsm,onFileReceived the name is null ,return")
                return;
            }

            if (fileName != obj) {
                Log.d("wangsm_bt", " wangsm,onFileReceived fileName != obj , return")
                return;
            }
            //end by bb fileName
            fileName?.let {
                d("File got success : $it")

                fileGetCallBack?.onFileGetSuccess(File(path))
                fileGetCallBack = null
            }
        }
    }

    interface ConnectCallBack {
        fun onConnectResult(z: Boolean)

        fun onDeviceAlreadyConnected()

        fun onServiceDiscovered()
    }

    interface FileDeleteCallBack {
        val fileName: String

        fun onFileDeleteFailed()

        fun onFileDeleteSuccess()
    }

    interface FileGetCallBack {
        val fileName: String

        fun onFileGetFailed()

        fun onFileGetSuccess(file: File)
    }

    interface FileSendCallBack {
        val file: File

        fun onFileSendFailed()

        fun onFileSendSuccess()
    }


    private fun getFileType(vType: XOSSSGFileHelper.FILETYPE): Int {
        var vRet = 0
        vRet = when (vType) {
            XOSSSGFileHelper.FILETYPE.FIT -> {
                1
            }

            XOSSSGFileHelper.FILETYPE.GNSS -> {
                2
            }

            XOSSSGFileHelper.FILETYPE.JSON -> {
                3
            }

            else -> {
                -1
            }
        }
        return vRet
    }

    fun onDeviceDisconnect() {
    }

    fun getGnssExpiredTime() = this.gnssExpiredTime

    fun init(address: String?, name: String?, type: Int) {
        this.address = address
        this.deviceName = name
        this.deviceType = type
        fitParser.setAddress(address)
        val bleCompatScannerUtil = this.dfuDeviceScanner
        bleCompatScannerUtil?.cancel()
        val incrementAddress = BleUtils.incrementAddress(address)
        this.dfuDeviceScanner = BleCompatScannerUtil(incrementAddress, 20000L, {})
        xossDeviceController?.unregisterXossDeviceListener(this.xossDeviceListener)
        xossDeviceController =
            DeviceControllerHelper.getXossDeviceController(address, this.deviceName, type)
        xossDeviceController?.apply {
            registerXossDeviceListener(xossDeviceListener)
            setLogger(TransLogger.getInstance())
        }
        DeviceHelper.registerConnectionStateListener(this.connectionListener)
    }

    fun refreshDeviceStateAndConnect(connectCallBack: ConnectCallBack?) {
        if (isConnected) {
            if (isDeviceFree) {
                applyUIState(DeviceUIState.CONNECTED)
            } else if (isDeviceInTransmission) {
                val fileTypeInTransmission = fileTypeInTransmission.ordinal
                Log.d("wangsm_bt", " wangsm,fileTypeInTransmission: $fileTypeInTransmission")
                when (fileTypeInTransmission) {
                    1 -> {
                        applyUIState(DeviceUIState.SYNCING_WORKOUT)
                    }

                    2 -> {
                        applyUIState(DeviceUIState.SYNCING_GNSS)
                    }

                    3 -> {
                        Log.d("wangsm_bt", " wangsm,refreshDeviceStateAndConnect SYNCING ")
                        applyUIState(DeviceUIState.SYNCING)
                    }

                    else -> {
                        Log.d("wangsm_bt", " wangsm,refreshDeviceStateAndConnect  2 SYNCING ")
                        applyUIState(DeviceUIState.SYNCING)
                    }
                }
            }
            if (connectCallBack == null) {
                return
            }
            connectCallBack.onDeviceAlreadyConnected()
            return
        }
        if (this.xossDeviceController != null) {
            if (!isConnecting1 && !isConnected) {
                connect(connectCallBack)
            } else if (isConnected) {
                applyUIState(DeviceUIState.CONNECTED)
            }
        }
        applyUIState(DeviceUIState.CONNECTING)
    }

    private val isConnecting1: Boolean
        get() {
            val xossDeviceController = this.xossDeviceController
            if (xossDeviceController != null) {
                return xossDeviceController.isConnecting
            }
            return false
        }

    private val isConnected: Boolean
        get() {
            val xossDeviceController = this.xossDeviceController
            if (xossDeviceController != null) {
                return xossDeviceController.isConnected
            }
            return false
        }

    val isBounded: Boolean
        get() {
            var address = xossDeviceController?.address
            if (address == null) {
                address = ""
            }
            return BleBondUtil.isThisDeviceBounded(address)
        }

    fun connect(connectCallBack: ConnectCallBack?) {
        this.connectCallBack = connectCallBack
        xossDeviceController?.connect()
    }

    fun disConnect() {
        xossDeviceController?.disconnect()
    }

    val lastTransmissionTime: Long
        get() {
            return xossDeviceController?.lastTransmissionTime ?: 0L
        }

    val fileTypeInTransmission: XOSSSGFileHelper.FILETYPE
        get() {
            val companion = XOSSSGFileHelper.FILETYPE.companion
            val currentFileNameInTransfer = xossDeviceController?.currentFileNameInTransfer ?: ""
            return companion.from(currentFileNameInTransfer)
        }

    fun innerRemoveDeviceFromLocal() {
        val boundedDevice = BleBondUtil.getBoundedDevice(
            this.address
        )
        if (boundedDevice != null && !BleBondUtil.internalRemoveBond(boundedDevice)) {
            SharedManager.getInstance().addRemoveFailedDevice(boundedDevice.address)
        }
        xossDeviceController?.let {
            it.isDisConnectFromUser = true
            it.disconnect()
            it.close()
        }
        val str = this.address ?: ""
        val byAddress = Device.getByAddress(str)
        byAddress?.delete()
        DeviceContext.startAndRefreshAutoConnector()
    }

    fun removeDevice(z: Boolean) {
        if (z) {
            getDeviceStatus { result ->
                if (4 == result) {
                    innerRemoveDeviceFromLocal()
                    removeDeviceStateLiveEvent.postValue(true)
                } else {
                    removeDeviceStateLiveEvent.postValue(false)
                }
            }
        } else {
            innerRemoveDeviceFromLocal()
            removeDeviceFromServer()
            removeDeviceStateLiveEvent.postValue(true)
            val tempAddress = address ?: ""
            val tempName = deviceName ?: ""
            val deviceType = deviceType
            XossDeviceAutoSyncManager.refreshTimerTask(tempAddress, tempName, deviceType)
        }
    }

    fun removeDeviceByUnBond() {
        xossDeviceController?.isDisConnectFromUser = true
        xossDeviceController?.disconnect()
        xossDeviceController?.close()
        removeDevice(false)
        ToastUtils.showLong(R.string.st_please_repair_it)
    }

    fun removeDeviceFromServer() {
        xossDeviceController?.let {
//            val companion: XPairRepository = XPairRepository.Companion.getInstance()
            val tempSerial = it.serial ?: ""
            val tempModel = it.model ?: ""
            val tempManufacturer = it.manufacturer ?: ""
            val tempAddress = it.address ?: ""
            val tempName = it.name ?: ""
            val tempHardVersion = it.hardwareVersion ?: ""
//            companion.unBoundDevice(XPairDeviceBoundParam(tempSerial,tempModel,tempManufacturer,tempAddress,tempName,tempHardVersion),{
//
//            })

        }
    }

    fun getFile(
        fileGetCallBack: FileGetCallBack, deviceUIState: DeviceUIState
    ) {
        viewModelScope.launch {
            Log.d("wangsm_bt", " wangsm,getFile lock begin  ")
            this@DeviceViewModel.fileGetCallBack = fileGetCallBack;
            mutex.lock()

            if (isConnected && isDeviceFreeAndNotInTransmission) {
                applyUIState(deviceUIState)
                //XossDevice
                Log.d("wangsm_bt", " wangsm,getFile lock entry  ")
                xossDeviceController?.getFile(fileGetCallBack.fileName)
            }
            Log.d("wangsm_bt", " wangsm,getFile unlock ")
            mutex.unlock()
        }
    }

    fun sendFile(
        fileSendCallBack: FileSendCallBack, deviceUIState: DeviceUIState
    ) {
        viewModelScope.launch {
            mutex.lock()
            if (isConnected && isDeviceFreeAndNotInTransmission) {
                applyUIState(deviceUIState)
                xossDeviceController?.getFile(fileSendCallBack.file.absolutePath)
            }
            mutex.unlock()
        }
    }

    private fun deleteFile(
        fileDeleteCallBack: FileDeleteCallBack, deviceUIState: DeviceUIState
    ) {
        viewModelScope.launch {
            mutex.lock()
            if (isConnected && isDeviceFreeAndNotInTransmission) {
                applyUIState(deviceUIState)
                xossDeviceController?.delete(fileDeleteCallBack.fileName)
            }
            mutex.unlock()
        }
    }

    fun syncFit(workout: Workout?, continuation: Continuation<File?>?): Any {/*
        SafeContinuation safeContinuation = new SafeContinuation(IntrinsicsKt.intercepted(continuation));
        final SafeContinuation safeContinuation2 = safeContinuation;
        getFile(new FileGetCallBack() {
            @Override
            public String getFileName() {
                return Workout.this.getTimestampInYHDHMS() + '.' + XOSSSGFileHelper.FILETYPE.FIT.getSuffix();
            }

            @Override
            public void onFileGetSuccess(File file) {
                Intrinsics.checkNotNullParameter(file, "file");
                Continuation<File> continuation2 = safeContinuation2;
                Result.Companion companion = Result.Companion;
                continuation2.resumeWith(Result.m2854constructorimpl(file));
            }

            @Override
            public void onFileGetFailed() {
                Continuation<File> continuation2 = safeContinuation2;
                Result.Companion companion = Result.Companion;
                continuation2.resumeWith(Result.m2854constructorimpl(ResultKt.createFailure(new FileNotFoundException("Sync " + Workout.this.getTimestampInYHDHMS() + ".fit failed"))));
            }
        }, XossDeviceConstants.DeviceUIState.SYNCING_WORKOUT);
        Object orThrow = safeContinuation.getOrThrow();
        if (orThrow == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
            DebugProbesKt.probeCoroutineSuspended(continuation);
        }
        return orThrow;
*/
        return ""
    }

    fun deleteDeletableList(
        iDeletable: IDeletable,
        deleteStartCallBack: (IDeletable) -> Unit,
        deleteAllDoneCallBack: () -> Unit
    ) {
        execute({ deleteFile(iDeletable) }, {}, { deleteAllDoneCallBack() }, true)
    }

    private suspend fun deleteFile(deletable: IDeletable): Boolean {
        deleteFile(object : FileDeleteCallBack {
            override val fileName: String
                get() = deletable.fileNameForDelete

            override fun onFileDeleteFailed() {
                TODO("Not yet implemented")
            }

            override fun onFileDeleteSuccess() {
                TODO("Not yet implemented")
            }

        }, DeviceUIState.SYNCING)
        return true
    }

    fun syncWorkoutList(
        workouts: Workouts, list: List<Workout>?, doneCallBack: () -> Unit
    ) {
        var arrayList: List<Workout>? = null
        /*      workouts.workouts?.let {//workoutList
                  val list = mutableListOf<Workout>()
                  for (obj in it) {
                      Log.d("wangsm_bt" , " syncWorkoutList, obj state=: " + obj.state);
                      if (obj.state == WorkoutState.UnSynced) {
                          Log.d("wangsm_bt" , " syncWorkoutList, obj=: " + obj.toString());
                          list.add(obj)
                      }
                  }
              }*/
        arrayList = list
        val sb = StringBuilder("need Sync: ")
        arrayList?.let {
            sb.append(it.size)
        }
        d(sb.toString())
        Log.d("wangsm_bt", " syncWorkoutList, sb=: " + sb.toString());
        if (null == arrayList) {
            Log.d("wangsm_bt", " syncWorkoutList, arrayList is null ");
            doneCallBack()
            applyUIState(DeviceUIState.CONNECTED)
            return
        }
    }

    private fun getWorkoutList(z: Boolean, doneCallBack: (Boolean) -> Unit) {
        getFile(object : FileGetCallBack {
            override val fileName: String = XOSSSGFileHelper.FILE.WORKOUT.fileName

            override fun onFileGetFailed() {
                val sb = StringBuilder(xossDeviceController?.name ?: "")
                sb.append(": Get Workouts File failed")
                tipsMutableLiveData.postValue(TipAction(sb.toString(), false))
                Log.d("wangsm_bt", " wangsm,Get Workouts File failed  ")
                doneCallBack(false)
            }

            override fun onFileGetSuccess(file: File) {
                viewModelScope.launch {
                    Log.d("wangsm_bt", " wangsm,onFileGetSuccess: file dir ${file.absoluteFile} ")
                    val workouts = GsonUtils.fromJson(readText(file), Workouts::class.java)
                    //test code
                    //Log.d("wangsm_bt"," wangsm,onFileGetSuccess: device_model=  ${workouts.device_model} ")
                    // Log.d("wangsm_bt"," wangsm,onFileGetSuccess: device_model=  ${workouts.sn} ")
                    //end test code
                    workoutListFlow.emit(workouts)
                    if (z) {
                        syncWorkoutList(workouts, null) {}
                    }
                    doneCallBack(true)
                }
            }

        }, deviceUIStateStateFlow.value)
    }

    fun getRouteBookList() {
        val path = isRouteBookJsonExist()
        try {
            if (null != path) {
                val readText = File(path).readText()
                executeIO {
                    val result = GsonUtils.fromJson(readText, Routebooks::class.java)
                    routeBookListFlow.emit(result)
                }
            } else {
                executeIO {
                    routebooksNotExist.emit(true)
                }
            }
        } catch (e: Throwable) {
            executeIO {
                exceptionMessage.emit(R.string.sync_routebook_exception)
            }
        }
    }

    val commonSetting: Unit
        get() {
        }

    val userProfileSetting: Unit
        get() {
        }

    val deviceLog: Unit
        get() {
        }

    fun sendUserProfileSettingFile(file: File) {
    }

    fun sendCommonSettingFile(file: File) {
    }

    fun sendGearSettingFile(file: File) {
    }

    fun sendRoutebookFile(j: Long, file: File) {
    }

    val gearProfileSetting: Unit
        get() {
        }

    val panelsSetting: Unit
        get() {
        }

    fun sendPanelFile(file: File) {
    }

    fun requestDeviceRecordState(b: Byte, callBack: (Int) -> Unit) {
        viewModelScope.launch {
            xossDeviceController?.execute(Commands.create(117, byteArrayOf(b)), 5000L)?.let {
                callBack(it.status)
                catchStatus(it.cmd, it.content)
            }
        }
    }

    private val deviceState: Int
        get() {
            return xossDeviceController?.deviceState ?: 17
        }

    val isDeviceFreeAndNotInTransmission: Boolean
        get() = isDeviceFree && !isDeviceInTransmission

    private val isDeviceFree: Boolean
        get() = deviceState == 17

    private val isDeviceInTransmission: Boolean
        get() = deviceState == 18

    fun abortDeviceTransmission() {
        if (!isDeviceInTransmission || null == xossDeviceController) {
            return
        }
        xossDeviceController?.abort()
    }

    fun getDeviceStatus(callBack: (Int) -> Unit) {
        if (isDeviceFreeAndNotInTransmission) {
            callBack(-1)
        } else {
            xossDeviceController?.let {
                it.response?.let { res ->
                    catchStatus(res.cmd, res.content)
                    callBack(res.status)
                }
            }
        }
    }

    suspend fun getDeviceMemoryUsage() {
        xossDeviceController?.let {
            it.response?.let { res ->
                catchStatus(res.cmd, res.content)
                res.content?.let { content ->
                    val list = String(content).split("/")
                    val pair = Pair(list[0].toLong(), list[1].toLong())
                    memoryUsageFlow.emit(pair)
                }
            }
        }
    }

    private fun getDeviceFirmwareDetailEntity(z: Boolean) {
    }

    fun refreshGNSSExpiredTimeFromDevice(z: Boolean, doneCallBack: () -> Unit) {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                xossDeviceController?.let {
                    val execute = it.execute(Commands.create(119, null))
                    execute?.let { res ->
                        catchStatus(res.cmd, res.content)
                        val content = res.content
                        content?.let { con ->
                            val ret = ByteArrayExtKt.readUInt32LE(con, 2)
                            gnssExpiredTime.emit(ret)
                        }
                    }
                }
            }
        }
    }

    fun syncSatelliteGNSSDate(
        context: Context, expiredTime: Int, doneCallBack: (Boolean) -> Unit
    ) {
        viewModelScope.launch {/*    //test remove by bb
            applyUIState(DeviceUIState.SYNCING_GNSS)
            Log.d("wangsm_bt"," syncSatelliteGNSSDate" )
            val ret = withContext(Dispatchers.IO) {
                XossDeviceRepository.getInstance().getGNSSInfo()
            }
            gNSSInfoFlow.emit(ret)*/
            //add by bb

        }
        doneCallBack(true)//add by bb
    }

    fun resetDevice(b: Byte, callBack: (Int) -> Unit) {
        viewModelScope.launch {
            xossDeviceController?.isDisConnectFromUser = true
            xossDeviceController?.let {
                val execute = it.execute(Commands.create(-52, byteArrayOf(b)))
                execute?.let { res ->
                    catchStatus(res.cmd, res.content)
                    val con = res.content
                    con?.let {
                        callBack(
                            ByteArrayExtKt.readInt8(
                                con, 0
                            )
                        )
                    }
                }
            }
        }
    }

    fun autoInitDevice(z: Boolean) {
        val str = this.address ?: ""
        if (!BleBondUtil.isThisDeviceBounded(str)) {
            Log.d("wangsm_bt", " autoInitDevice,return")
            return
        }

        Log.d("wangsm_bt", " autoInitDevice,begin launch")

        viewModelScope.launch {
            Log.d("wangsm_bt", " autoInitDevice lock")
            mutex.lock()

            requestMtu(BesSdkConstants.DEFAULT_MTU) {
                Log.d("wangsm_bt", " autoInitDevice requestMtu")
                viewModelScope.launch {
                    readDis {
                        Log.d("wangsm_bt", " autoInitDevice readDis")
                        sendTime {
                            Log.d("wangsm_bt", " autoInitDevice sendTime")
                            syncProfile(z) {
                                Log.d("wangsm_bt", " autoInitDevice syncProfile")
                                initDeviceInfo {
                                    Log.d("wangsm_bt", " autoInitDevice initDeviceInfo")
                                    syncSatelliteGNSSDate(BaseApplication.get(), 0) {
                                        Log.d("wangsm_bt", " autoInitDevice syncSatelliteGNSSDate")
                                        if (SharedManager.getInstance()
                                                .isThisDeviceAutoSync(address, true) || z
                                        ) {
                                            Log.d("wangsm_bt", "   getWorkoutList")
                                            getWorkoutList(z) {}
                                        }
                                        Log.d("wangsm_bt", " autoInitDevice,end")
                                        xossDeviceController?.setIsInit(true)
                                    }
                                }
                            }
                        }
                    }
                }
            }
            mutex.unlock()
        }
    }

    private fun requestMtu(i: Int, doneCallBack: () -> Unit) {
        Log.d("wangsm_bt", " wangsm,requestMtu SYNCING ")
        applyUIState(DeviceUIState.SYNCING)
        xossDeviceController?.requestMtu(i) { _, _ ->
            applyUIState(DeviceUIState.CONNECTED)
            Log.d("wangsm_bt", " wangsm,requestMtu to invoke ")
            doneCallBack.invoke()
        }
    }

    private suspend fun readDis(doneCallBack: () -> Unit) {
        when (deviceUIStateStateFlow.value) {
            DeviceUIState.OFFLINE -> {
                Log.d("wangsm_bt", " wangsm,readDis SYNCING ")
                applyUIState(DeviceUIState.SYNCING)
                applyProgress(10.0f)
                delay(delayInPeer)
            }

            DeviceUIState.OFFLINE_CONNECTION_LOST -> {

            }

            DeviceUIState.CONNECTING -> {}
            DeviceUIState.CONNECT_FAIL -> {}
            DeviceUIState.CONNECTED -> {}
            DeviceUIState.SYNCING -> {}
            DeviceUIState.SYNCING_WORKOUT -> {
                Log.d("wangsm_bt", " wangsm,readDis: SYNCING_WORKOUT ")
            }

            DeviceUIState.SYNCING_GNSS -> {}
            DeviceUIState.BUSY -> {}
            DeviceUIState.DFU -> {}
            DeviceUIState.INITIALZING -> {}
            DeviceUIState.UNKNOWN -> {}
        }
        doneCallBack()
    }

    fun sendTime(doneCallBack: () -> Unit) {
        /*        viewModelScope.launch {
                    Log.d("wangsm_bt"," wangsm,sendTime SYNCING ")
                    applyUIState(DeviceUIState.SYNCING)
                    val currentTimeMillis = (System.currentTimeMillis() / 1000).toInt()
                    d("send Time: $currentTimeMillis")
                    val bytes = ByteArray(4)
                    ByteUtils.intToBytesLE(currentTimeMillis, bytes, 0)
                    xossDeviceController?.let {
                        val execute = it.execute(Commands.create(84, bytes))
                        execute?.let { res ->
                            catchStatus(res.cmd, res.content)
                            applyUIState(DeviceUIState.CONNECTED)
                            doneCallBack()
                        }
                    }
                }*/
        doneCallBack()
    }

    fun syncProfile(z: Boolean, doneCallBack: () -> Unit) {
        Log.d("wangsm_bt", " wangsm,syncProfile ")
        if (z) {
            doneCallBack()
        } else {
            getFile(object : FileGetCallBack {
                override val fileName: String = XOSSSGFileHelper.FILE.USERPROFILE.fileName

                override fun onFileGetFailed() {
                }

                override fun onFileGetSuccess(file: File) {
                }

            }, deviceUIStateStateFlow.value)
        }
    }

    fun initDeviceInfo(doneCallBack: () -> Unit) {
        viewModelScope.launch {}
        doneCallBack()//add by bb
    }

    val deviceModel: String
        get() {
            val xossDeviceController = this.xossDeviceController
            val model = xossDeviceController?.model
            return model ?: ""
        }

    val deviceHardwareVersion: String
        get() {
            val xossDeviceController = this.xossDeviceController
            val hardwareVersion = xossDeviceController?.hardwareVersion
            return hardwareVersion ?: ""
        }

    val deviceSerialNumber: String
        get() {
            val xossDeviceController = this.xossDeviceController
            val serial = xossDeviceController?.serial
            return serial ?: ""
        }

    val manufacturer: String
        get() {
            val xossDeviceController = this.xossDeviceController
            val manufacturer = xossDeviceController?.manufacturer
            return manufacturer ?: ""
        }

    val firmwareVersion: String
        get() {
            val xossDeviceController = this.xossDeviceController
            val firmwareVersion = xossDeviceController?.firmwareVersion
            return firmwareVersion ?: ""
        }

    fun applyUIState(deviceUIState: DeviceUIState) {
        viewModelScope.launch {
            Log.d("wangsm_bt", " wangsm,applyUIState ")
            deviceUIStateStateFlow.emit(deviceUIState)
        }
    }

    fun applyProgress(f: Float) {
        viewModelScope.launch {
            progressStateFlow.emit(f)
        }
    }

    fun d(msg: String?) {
        val xossDeviceController = this.xossDeviceController
        Log.d(xossDeviceController?.name, msg)
    }

    fun e(msg: String?, th: Throwable?) {
        val xossDeviceController = this.xossDeviceController
        Log.e(xossDeviceController?.name, msg, th)
    }

    public override fun onCleared() {
        super.onCleared()
        this.xossDeviceController?.unregisterXossDeviceListener(this.xossDeviceListener)
        DeviceHelper.unregisterConnectionStateListener(connectionListener)
        val bleCompatScannerUtil = this.dfuDeviceScanner
        bleCompatScannerUtil?.cancel()
        fitParser.release();
    }

    fun catchStatus(b: Byte, bArr: ByteArray?) {
        val first = bArr?.first() ?: (-10086.toByte()).toByte()
        if (b.toInt() != -84) {
            if (b.toInt() != 4) {
                return
            }
            applyUIState(DeviceUIState.CONNECTED)
        } else if (first.toInt() == -1) {
            applyUIState(DeviceUIState.CONNECTED)
        } else if (first.toInt() == 0) {
            applyUIState(DeviceUIState.BUSY)
        } else if (first.toInt() == 1) {
            applyUIState(DeviceUIState.BUSY)
        } else {
            applyUIState(DeviceUIState.BUSY)
        }
    }

    private fun isRouteBookJsonExist(): String? {
        val sn = SettingsJsonUtils.getSn(getApplication())
        val model = SettingsJsonUtils.getDeviceModel(getApplication())

        val extraPath = FileUtils.checkExternalDirectoryPathExist(
            true, model,
            sn,
            SettingsJsonUtils.ROUTE_BOOKS_FOLDER,
            SettingsJsonUtils.ROUTE_BOOKS_JSON
        )
        return extraPath
    }
    /*    fun getWorkoutListFlow(): MutableSharedFlow<Workouts> {
            return workoutListFlow
        }*/
}